package edu.njit.hz278.tictactoe;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.webkit.WebView;
import android.widget.Toast;

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 * 
 * @see SystemUiHider
 */
@SuppressLint("SetJavaScriptEnabled")
public class WelcomeActivity extends Activity {

	private WebView contentView;
	WelcomeActivity self = this;
	private Handler handler;
	private Thread mythread;
	private volatile Communicator comm;

	Queue<Map<String, Object>> workq = new LinkedBlockingQueue<Map<String, Object>>();

	private String currAction;

	private void initWebBrowser() {
		contentView = (WebView) findViewById(R.id.webview);

		contentView.getSettings().setJavaScriptEnabled(true);
		contentView.addJavascriptInterface(new WebAppInterface(self,
				contentView), "Android");

		contentView.loadUrl("file:///android_asset/welcome.html?key="
				+ System.currentTimeMillis());
		
		/*
		contentView.loadUrl("http://10.0.2.2/tic/welcome.html?key="
				+ System.currentTimeMillis());
				*/

	}

	void addTask(Map<String, Object> data) {

		if (Constants.ACTION_MOVE.equals(data.get("action"))
				&& Constants.ACTION_WAIT_FOR_MOVE.equals(currAction)) {
			Log.i("javascript deny task", data.toString());
			return;
		}

		Log.i("javascript add task", data.toString());
		workq.add(data);
		currAction = (String) data.get("action");
	}

	private void handleState(int ret, Object state) {
		if (state == null)
			return;

		Message msg = handler.obtainMessage(ret, state);
		msg.sendToTarget();
	}

	private void initSocketThread() {
		mythread = new Thread(new Runnable() {

			private final Object dummy = new Object();

			private int signIn(Map<String, Object> arg) {
				String userid = (String) arg.get("userid");
				String passwd = (String) arg.get("passwd");
				return comm.signIn(userid, passwd);
			}

			private int signUp(Map<String, Object> arg) {
				String userid = (String) arg.get("userid");
				String passwd = (String) arg.get("passwd");
				return comm.signUp(userid, passwd);
			}

			private int createGame(Map<String, Object> arg) {
				String roomname = (String) arg.get("name");
				String passwd = (String) arg.get("passwd");

				if (roomname == null || roomname.length() == 0) {
					if (passwd == null || passwd.length() == 0)
						return comm.createRoom().getId();
					else
						return comm.createRoom(null, passwd).getId();
				} else {
					if (passwd == null || passwd.length() == 0)
						return comm.createRoom(roomname).getId();
					else
						return comm.createRoom(roomname, passwd).getId();
				}

			}

			private int move(Map<String, Object> arg) {
				int row = Integer.parseInt((String) arg.get("row"));
				int col = Integer.parseInt((String) arg.get("col"));
				arg.put("result", comm.move(row, col));
				return 1;
			}

			private int waitForMove(Map<String, Object> arg) {
				int[] pos = new int[2];
				String status = comm.waitForMove(pos);
				arg.put("result", status);
				arg.put("position", pos);

				return 1;
			}

			private int lsrooms(Map<String, Object> arg) {
				arg.put("rooms", comm.lsRooms());
				return 1;
			}
			
			private int rankings(Map<String, Object> arg) {
				comm.rankings(arg);
				return 1;
			}

			private int join(Map<String, Object> arg) {
				int roomid = (Integer) arg.get("roomid");
				int aid = (Integer) arg.get("aid");
				String passwd = (String) arg.get("roompasswd");

				boolean ret;
				if (passwd == null || passwd.length() == 0)
					ret = comm.joinRoom(roomid, aid);
				else
					ret = comm.joinRoom(roomid, aid, passwd);

				return ret ? 1 : 0;
			}

			@Override
			public void run() {

				if (comm == null) {
					synchronized (dummy) {
						if (comm == null)
							comm = new Communicator();
					}
				}

				while (true) {
					while (workq.peek() != null) {
						Map<String, Object> param = workq.remove();
						Log.i("inside thread", param.toString());
						String act = (String) param.get("action");
						int state = 0;
						if (Constants.ACTION_SIGN_IN.equals(act))
							state = signIn(param);
						else if (Constants.ACTION_NEW_USER.equals(act))
							state = signUp(param);
						else if (Constants.ACTION_CREAT_ROOM.equals(act))
							state = createGame(param);
						else if (Constants.ACTION_MOVE.equals(act))
							state = move(param);
						else if (Constants.ACTION_WAIT_FOR_RIVAL.equals(act)) {
							state = comm.waitForRival();
							String username = comm.getUser(state).getUserid();
							param.put("rivalname", username);
						} else if (Constants.ACTION_WAIT_FOR_MOVE.equals(act))
							state = waitForMove(param);
						else if (Constants.ACTION_LS_ROOM.equals(act))
							state = lsrooms(param);
						else if (Constants.ACTION_JOIN.equals(act))
							state = join(param);
						else if(Constants.ACTION_LEADER_BOARD.equals(act))
							state = rankings(param);
						self.handleState(state, param);
					}
				}
			}
		});

		mythread.start();
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_welcome);
		initWebBrowser();
		initSocketThread();

		handler = new Handler(Looper.getMainLooper()) {

			/*
			 * handleMessage() defines the operations to perform when the
			 * Handler receives a new Message to process.
			 */
			@SuppressWarnings("unchecked")
			@Override
			public void handleMessage(Message inputMessage) {
				int what = inputMessage.what;
				Map<String, Object> ret = (Map<String, Object>) inputMessage.obj;

				Log.i("handlemsg", currAction);

				if (Constants.ACTION_SIGN_IN.equals(currAction)) {
					int uid = what;
					if (uid == 0)
						Toast.makeText(self, Constants.RES_USER_PW_WRONG,
								Toast.LENGTH_SHORT).show();
					else {
						contentView.loadUrl(String.format(
								"javascript:proceed_to_mode('%s')",
								ret.get("userid")));
						Toast.makeText(self,
								"Welcome back, " + ret.get("userid"),
								Toast.LENGTH_SHORT).show();
					}
				} else if (Constants.ACTION_NEW_USER.equals(currAction)) {
					int uid = what;
					if (uid == 0)
						Toast.makeText(self, Constants.RES_DUP_USERNAME,
								Toast.LENGTH_SHORT).show();
					else
						contentView.loadUrl(String.format(
								"javascript:proceed_to_mode('%s')",
								ret.get("userid")));
				} else if (Constants.ACTION_CREAT_ROOM.equals(currAction)) {
					int roomid = what;
					if (roomid == 0)
						Toast.makeText(self, Constants.RES_CREAT_ERR,
								Toast.LENGTH_SHORT).show();
					else {
						Map<String, Object> param = new HashMap<String, Object>();
						param.put("action", Constants.ACTION_WAIT_FOR_RIVAL);
						addTask(param);
						contentView.loadUrl("javascript:proceed_to_board()");
					}

				} else if (Constants.ACTION_WAIT_FOR_RIVAL.equals(currAction)) {

					String rivalName = (String) ret.get("rivalname");
					Toast.makeText(self, rivalName + Constants.RES_HAS_ENTERED,
							Toast.LENGTH_SHORT).show();

					contentView.loadUrl(String.format(
							"javascript:tellBoardRival('%s')", rivalName));

				} else if (Constants.ACTION_JOIN.equals(currAction)) {
					if (what == 0) {
						Toast.makeText(self, Constants.RES_JOIN_FAILED,
								Toast.LENGTH_SHORT).show();

						// TODO need to refresh game list
					} else {
						String ownername = (String) ret.get("ownerid");
						Map<String, Object> param = new HashMap<String, Object>();
						param.put("action", Constants.ACTION_WAIT_FOR_MOVE);
						addTask(param);
						Log.i("hello", "wtf");
						contentView.loadUrl(String.format(
								"javascript:tellBoardOwner('%s')", ownername));
					}

				} else if (Constants.ACTION_MOVE.equals(currAction)) {
					String status = (String) ret.get("result");
					Log.i("move result", status);
					// youwin/youlose/draw/ok/oops/notready

					if ("notready".equals(status)) {
						Toast.makeText(self, Constants.RES_NOT_READY,
								Toast.LENGTH_SHORT).show();
						return;
					}
					if ("oops".equals(status)) {
						Toast.makeText(self, Constants.RES_NOT_YOUR_TURN,
								Toast.LENGTH_LONG).show();
						return;
					}

					if ("ok".equals(status)) {

						Map<String, Object> param = new HashMap<String, Object>();
						param.put("action", Constants.ACTION_WAIT_FOR_MOVE);
						addTask(param);

					} else if ("youwin".equals(status)) {

						Toast.makeText(self, Constants.RES_YOU_WIN,
								Toast.LENGTH_LONG).show();
						contentView.loadUrl("javascript:go_back_mode()");

					} else if ("youlose".equals(status)) {

						Toast.makeText(self, Constants.RES_YOU_LOSE,
								Toast.LENGTH_LONG).show();
						contentView.loadUrl("javascript:go_back_mode()");

					} else if ("draw".equals(status)) {

						Toast.makeText(self, Constants.RES_YOU_DRAW,
								Toast.LENGTH_LONG).show();
						contentView.loadUrl("javascript:go_back_mode()");

					}

					contentView.loadUrl(String.format(
							"javascript:draw_mine(%d, %d)",
							Integer.valueOf((String) ret.get("row")),
							Integer.valueOf((String) ret.get("col"))));

				} else if (Constants.ACTION_WAIT_FOR_MOVE.equals(currAction)) {
					String status = (String) ret.get("result");
					Log.i("other move", status);

					if ("notready".equals(status)) {
						Toast.makeText(self, Constants.RES_NOT_READY,
								Toast.LENGTH_SHORT).show();
						return;
					}
					if ("oops".equals(status)) {
						Toast.makeText(self, Constants.RES_NOT_YOUR_TURN,
								Toast.LENGTH_SHORT).show();
						return;
					} else if ("youwin".equals(status)) {

						Toast.makeText(self, Constants.RES_YOU_WIN,
								Toast.LENGTH_LONG).show();
						contentView.loadUrl("javascript:go_back_mode()");

					} else if ("youlose".equals(status)) {

						Toast.makeText(self, Constants.RES_YOU_LOSE,
								Toast.LENGTH_LONG).show();
						contentView.loadUrl("javascript:go_back_mode()");

					} else if ("draw".equals(status)) {

						Toast.makeText(self, Constants.RES_YOU_DRAW,
								Toast.LENGTH_LONG).show();
						contentView.loadUrl("javascript:go_back_mode()");

					}

					int[] pos = (int[]) ret.get("position");

					contentView.loadUrl(String.format(
							"javascript:draw_other(%d, %d)", pos[0], pos[1]));
					currAction = "idle";

				} else if (Constants.ACTION_LS_ROOM.equals(currAction)) {
					Room[] rooms = (Room[]) ret.get("rooms");
					contentView.loadUrl(String.format(
							"javascript:populate_rooms(%s)",
							Arrays.toString(rooms)));
				} else if(Constants.ACTION_LEADER_BOARD.equals(currAction)) {
					User[] users = (User[]) ret.get("players");
					contentView.loadUrl(String.format(
							"javascript:populate_players(%s, %d, %d)",
							Arrays.toString(users), ret.get("myranking"), ret.get("myscore")));
				}
			}
		};
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		mythread.interrupt();
		if (comm != null)
			comm.close();
	}
}
